// 顶部：仅类型导入 + 拆分 logger 的值/类型导入
import type { IAmountParams, ICutParams, IRandomParams, IStrParams, IUtilsTo } from "./to";
import utilsIs from "../is";
import Logger from "../../logger";
import type { ILogger } from "../../logger";
import { LoggerLevel } from "../../logger";

export type {
    IUtilsTo,
    IAmountParams, ICutParams, IRandomParams, IStrParams,
}

class UtilsTo implements IUtilsTo {
    private logger: ILogger;

    constructor(level?: LoggerLevel) {
        this.logger = new Logger('UtilsTo', level);
    }

    formatCurrency(data: string | number): string {
        // 判断是否为有效数字
        if (!utilsIs.number(data)) {
            this.logger.warn('formatCurrency()', '传入的值不是有效数字');
            return '0';
        }

        // 将数据转换为字符串
        const valueStr = data.toString();

        // 判断是否为整数
        if (utilsIs.integer(data)) {
            // 整数部分添加千位分隔符
            return valueStr.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        } else {
            // 处理小数部分
            const [integerPart, decimalPart] = valueStr.split('.');
            // 整数部分添加千位分隔符
            const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
            // 返回格式化后的金额
            return `${formattedInteger}.${decimalPart}`;
        }
    }

    generateUUID(): string {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    generateUniqueTimestamp(): string {
        const timestamp = Date.now().toString(36);
        const random = Math.random().toString(36).substring(2, 5);
        return `${timestamp}${random}`;
    }

    getFirstChars(data: string, params?: IStrParams): string {
        params = params || {};
        const length = typeof params.length === "number" ? params.length : 1;
        if (!data.length) {
            this.logger.warn('getFirstChars()', '未找到数据')
            return ''
        }
        if (data.length < length) {
            this.logger.warn('getFirstChars()', '裁剪长度 > 数据长度');
            return data
        }
        return data.substring(0, length);
    }

    getLastChars(data: string, params?: IStrParams): string {
        params = params || {};
        const length = typeof params.length === "number" ? params.length : 1;
        if (!data.length) {
            this.logger.warn('getLastChars()', '未找到数据')
            return ''
        }
        if (data.length < length) {
            this.logger.warn('getLastChars()', '裁剪长度 > 数据长度');
            return data
        }
        return data.substring(data.length - length, data.length);
    }

    cutString(data: string, params?: ICutParams): string {
        params = params || {};
        const count: number = params.count || 10;
        const unit: string = params.unit || '...';
        const countLeft: number = typeof params.countLeft === "number" && utilsIs.integer(params.countLeft) ? params.countLeft : count;
        const countRight: number = typeof params.countRight === "number" && utilsIs.integer(params.countRight) ? params.countRight : count;
        if (!data.length) {
            this.logger.warn('cutString()', '未找到数据')
            return ''
        }
        if (data.length <= (countLeft + countRight)) {
            this.logger.warn('cutString()', '裁剪长度 > 数据长度');
            return data;
        }
        const left = data.substring(0, countLeft);
        const right = data.substring(data.length - countRight, data.length);
        return `${left}${unit}${right}`
    }

    formatAmount(data: string | number, params?: IAmountParams): string {
        params = params || {};
        //  判断金额
        const isAmount = utilsIs.amount(data, {isCanZero: true, isCanNegativeNum: true});
        if (!isAmount) {
            this.logger.warn('formatAmount()', `传入的值不是金额`)
            return '0'
        }
        //  是否金额转换
        const isConvert = typeof params.isConvert === "boolean" ? params.isConvert : true;
        //  最小值
        const min = typeof params.min === "number" ? params.min : 2;
        //  最大值
        const max = typeof params.max === "number" ? params.max : 2;
        //  小数位折叠
        const isDecimalFold = typeof params.isDecimalFold === "boolean" ? params.isDecimalFold : false;

        if (utilsIs.integer(data, {isCanZero: true, isCanNegativeNum: true})) {
            return Number(data).toFixed(min);
        } else {
            const valueStr = data.toString();
            const valueSplit = valueStr.split('.');
            const dotIndex = valueStr.indexOf('.');
            //  小数位折叠
            if (isDecimalFold) {
                let _value = valueSplit[0];
                const _decimal = valueSplit[1];
                let _compared = '0';
                for (let i = 0, len = _decimal.length; i < len; i++) {
                    if (_decimal.indexOf(_compared) === 0) _compared = `${_compared}0`;
                    else break;
                }
                const lengthCompared = _compared.length - 1;
                const lengthDecimal = _decimal.length;
                if (lengthCompared > 3) {
                    if (isConvert) _value = this.amountConvert(_value);
                    const lastLength = (lengthDecimal - lengthCompared) > 3 ? (lengthCompared + 3) : lengthDecimal;
                    return `${_value}.0{${lengthCompared}}${_decimal.substring(lengthCompared, lastLength)}`;
                }
            }
            //  小数点
            if (
                (dotIndex < 0) ||
                (valueStr.length - (dotIndex < 0 ? 0 : dotIndex) <= (min ?? 0))
            ) {
                // min 最小显示
                const valueMin = Number(data).toFixed(min);
                if (isConvert) return this.amountConvert(valueMin);
                return valueMin;
            } else {
                // max 最大显示
                let dotStr = `.${valueSplit[1].substring(0, max)}`;
                if (max === 0) dotStr = '';
                const valueStrMax = `${valueSplit[0]}${dotStr}`;
                if (isConvert) return this.amountConvert(valueStrMax);
                return valueStrMax;
            }
        }
    }

    amountConvert(data: string | number): string {
        //  判断金额
        const isAmount = utilsIs.amount(data, {isCanZero: true, isCanNegativeNum: true});
        if (!isAmount) {
            this.logger.warn('amountConvert()', `传入的值不是金额`)
            return '0'
        }
        const valueStr = data.toString();
        //金额转换 分->元 保留2位小数 并每隔3位用逗号分开 1,234.56
        let d = valueStr.indexOf(".");
        if (d < 0) d = valueStr.length;
        let intSum = valueStr.substring(0, d).replace(/\B(?=(?:\d{3})+$)/g, ',');//取到整数部分
        let dot = '';
        if (valueStr.indexOf(".") >= 0) dot = valueStr.substring(valueStr.length, valueStr.indexOf("."));//取到小数部分搜索
        return (intSum + dot).toString();
    }

    convertScientificNotation(data: string | number): string {
        data = Number(data);
        let m = data.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/) as any;
        return data.toFixed(Math.max(0, (m[1] || '').length - m[2]));
    }

    generateRandomNumber(params?: IRandomParams): string {
        params = params || {};
        const count = typeof params.count === 'number' ? params.count : 4;
        const data = Math.floor(Math.random() * Math.pow(10, count)).toString();
        if (data.length !== count) this.logger.warn('generateRandomNumber()', '生成长度不等于 count 值')
        return data;
    }

    shuffleArray<T>(arr: T[]): T[] {
        let i = arr.length;
        while (i) {
            let j = Math.floor(Math.random() * i--);
            [arr[j], arr[i]] = [arr[i], arr[j]];
        }
        return arr;
    }

    deepCopyJson<T>(data: T): T {
        if (!utilsIs.json(data)) return {} as T
        return JSON.parse(JSON.stringify(data));
    }

    deepCopyArray<T>(data: T[]): T[] {
        if (!utilsIs.array(data)) return [];
        const list: T[] = [];
        data.map(item => list.push(item));
        return list;
    }

    jsonToQueryString(data: any): string {
        if (!utilsIs.json(data)) return '';
        let value: string = '';
        for (const item in data) {
            if (!data.hasOwnProperty(item)) continue;
            value += `${item}=${data[item]}&`;
        }
        if (value) value = value.substring(0, value.length - 1);
        return value;
    }

    queryStringToJson<T>(search: string): T {
        const result: any = {} as T;
        if (!search.length) return result;
        const strA = search.indexOf('?') >= 0 ? search.split('?')[1] : search;
        const strB = strA.split('&');
        for (let i = 0, len = strB.length; i < len; i++) {
            const item = strB[i].split('=');
            result[item[0]] = typeof item[1] === 'undefined' ? '' : item[1];
        }
        return result;
    }

}

export default new UtilsTo() as IUtilsTo;
